Amazon RDS for MySQL でマルチソースレプリケーションを試してみた
こんにちは、森田です。
以下のアップデートでAmazon RDS for MySQL でマルチソースレプリケーションが可能となりました。
本記事では、実際に Amazon RDS for MySQL でのマルチソースレプリケーションの手順をご紹介します。
やってみた
今回は2つのRDSをソースとして、1つのRDSへレプリケーションを行います。
前提条件
本記事では、RDSインスタンス3つ(database-1, database-2, target)は作成済みとします。
作成したインスタンスは、マルチソースレプリケーション可能な 8.0.35 で作成しています。
パラメータグループは以下スクリプトで作成済みとします。
pg_name="rds-multi-source-replication" aws rds create-db-parameter-group \ --db-parameter-group-name $pg_name \ --db-parameter-group-family mysql8.0 \ --description $pg_name
バイナリログの有効化
バイナリログを用いてのレプリケーションを行っているため、バイナリログの有効化が必要となります。
以下をスクリプトを実行し、バイナリログが有効となるようパラメータグループを変更します。
pg_name="rds-multi-source-replication" aws rds modify-db-parameter-group \ --db-parameter-group-name $pg_name \ --parameters "ParameterName=log_bin,ParameterValue=ON,ApplyMethod=immediate" \ --parameters "ParameterName=binlog_format,ParameterValue=ROW,ApplyMethod=immediate"
ソースインスタンス側の設定
レプリケーションを行うため、ソースインスタンス側で以下の設定が必要です。
- ターゲットインスタンスがレプリケーションを行う際に利用するユーザ作成
- バイナリログ保持期間がnullとなっているため、任意の値の設定
- ソース DB インスタンスへの書き込み操作のブロック(read-only パラメータを ON)
これらを各ソースインスタンス側で設定を行うのは数が増えると面倒なため、スクリプトで行います。
endpoints=( "database-1.xxxx.ap-northeast-1.rds.amazonaws.com" "database-2.xxxx.ap-northeast-1.rds.amazonaws.com" ) passwords=( "xxx" "xxx" ) pg_names=( "rds-multi-source-replication" "rds-multi-source-replication" ) user_password="hogefuga1234" length=${#endpoints[@]} for (( i=0; i<$length; i++ )) do endpoint=${endpoints[$i]} password=${passwords[$i]} pg_name=${pg_names[$i]} mysql -h $endpoint -P 3306 -u admin -p$password -e \ "CREATE USER 'repl_user'@'%' IDENTIFIED BY '$user_password'; \ GRANT REPLICATION SLAVE ON <em>.</em> TO 'repl_user'@'%'; \ CALL mysql.rds_set_configuration('binlog retention hours', 24); " aws rds modify-db-parameter-group --db-parameter-group-name $pg_name \ --parameters "ParameterName=read_only,ParameterValue=1,ApplyMethod=immediate" done
上記を利用する際には、endpoints
、passwords
、pg_names
などを環境にあった値に変更する必要があります。
ソースインスタンスからターゲットインスタンスへのダンプ
mysqldump を使用して、ソース DB インスタンスからターゲットインスタンスにデータベースをコピーします。
また、レプリケーションを行う際にbinlogFileとPostionが必要となるため、出力を行います。
以下スクリプトで上記をまとめて実行していきます。
endpoints=( "database-1.xxxx.ap-northeast-1.rds.amazonaws.com" "database-2.xxxx.ap-northeast-1.rds.amazonaws.com" ) passwords=( "xxx" "xxx" ) databases=( "userdatabase" "productdatabase" ) target_endpoint="target.xxxx.ap-northeast-1.rds.amazonaws.com" target_password="hogefuga1234" length=${#endpoints[@]} for (( i=0; i<$length; i++ )) do endpoint=${endpoints[$i]} password=${passwords[$i]} database=${databases[$i]} mysqldump --databases $database \ --compress \ --set-gtid-purged=OFF \ --order-by-primary \ -u admin \ -p$password \ --host=$endpoint | mysql \ --host=$target_endpoint \ --port=3306 \ -u admin \ -p$target_password mysql -h $endpoint -P 3306 -u admin -p$password -e "SHOW MASTER STATUS;" done
+----------------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +----------------------------+----------+--------------+------------------+-------------------+ | mysql-bin-changelog.000066 | 534 | | | | +----------------------------+----------+--------------+------------------+-------------------+ +----------------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +----------------------------+----------+--------------+------------------+-------------------+ | mysql-bin-changelog.000067 | 534 | | | | +----------------------------+----------+--------------+------------------+-------------------+
ターゲットインスタンス側の設定
rds_set_external_source_for_channel
とrds_start_replication_for_channel
のストアドプロシージャを使って、レプリケーションを有効化します。
先ほど取得したbinlogの情報を以下スクリプトの上部に記載して実行します。
endpoints=( "database-1.xxxx.ap-northeast-1.rds.amazonaws.com" "database-2.xxxx.ap-northeast-1.rds.amazonaws.com" ) bin_files=( "mysql-bin-changelog.000066" "mysql-bin-changelog.000067" ) positions=( "534" "534" ) target_endpoint="target.xxx.ap-northeast-1.rds.amazonaws.com" target_password="hogefuga1234" user_password="hogefuga1234" length=${#endpoints[@]} for (( i=0; i<$length; i++ )) do source_endpoint=${endpoints[$i]} bin_file=${bin_files[$i]} bin_position=${positions[$i]} mysql -h $target_endpoint -P 3306 -u admin -p$target_password -e \ "\ CALL mysql.rds_set_external_source_for_channel( \ '$source_endpoint', \ 3306, \ 'repl_user', \ '$user_password', \ '$bin_file', \ $bin_position, \ 0, \ 'source$i'\ );\ CALL mysql.rds_start_replication_for_channel('source$i');\ " done
動作確認
ターゲットインスタンスでSHOW REPLICA STATUS\G
を実行すると、現在のレプリケーション状況が確認できます。
mysql> SHOW REPLICA STATUS\G *************************** 1. row *************************** Replica_IO_State: Waiting for master to send event Source_Host: database-1.czdia394lloi.ap-northeast-1.rds.amazonaws.com Source_User: repl_user Source_Port: 3306 Connect_Retry: 60 Source_Log_File: mysql-bin-changelog.000117 Read_Source_Log_Pos: 157 Relay_Log_File: relaylog-source0.000105 Relay_Log_Pos: 279 Relay_Source_Log_File: mysql-bin-changelog.000117 Replica_IO_Running: Yes Replica_SQL_Running: Yes *************************** 2. row *************************** Replica_IO_State: Waiting for master to send event Source_Host: database-2.xxxx.ap-northeast-1.rds.amazonaws.com Source_User: repl_user Source_Port: 3306 Connect_Retry: 60 Source_Log_File: mysql-bin-changelog.000118 Read_Source_Log_Pos: 534 Relay_Log_File: relaylog-source1.000105 Relay_Log_Pos: 656 Relay_Source_Log_File: mysql-bin-changelog.000118 Replica_IO_Running: Yes Replica_SQL_Running: Yes
ソースインスタンスへのinsert処理
ソースインスタンスは、read_onlyとなっているため、read_onlyをオフにします。
pg_name="rds-multi-source-replication" aws rds modify-db-parameter-group --db-parameter-group-name $pg_name \ --parameters "ParameterName=read_only,ParameterValue=0,ApplyMethod=immediate"
そのあとで、insertの実行を行います。
mysql> INSERT INTO users (name, email, password) VALUES \ -> ('Morita', 'morita@example.com', 'morita123'); Query OK, 1 row affected (0.15 sec)
ターゲットインスタンスのテーブル確認
ターゲットインスタンスに接続し、先ほどinsertを行ったusersテーブルを取得してみると、以下のようにレプリケーションが行えていることが確認できます。
mysql> select * from users; +----+----------------+--------------------+-----------+---------------------+ | id | name | email | password | created_at | +----+----------------+--------------------+-----------+---------------------+ | 1 | Alice Smith | alice@example.com | alice123 | 2024-02-29 09:42:53 | | 2 | Bob Johnson | bob@example.com | bob123 | 2024-02-29 09:42:53 | | 3 | Carol Williams | carol@example.com | carol123 | 2024-02-29 09:42:53 | | 4 | Morita | morita@example.com | morita123 | 2024-02-29 11:28:41 | +----+----------------+--------------------+-----------+---------------------+
最後に
レプリケーションを行うために少し前準備が必要ですが、データ分析やバックアップとしての用途としては活用できそうな機能となっています。
複数のインスタンスに対して処理を行う必要があるため、ぜひ今回作成したスクリプトを活用してみてください。
おまけ
何度か動作確認のため、レプリケーションの停止や削除を行なったため、その際に利用したストアドプロシージャも載せておきます。
レプリケーションの停止
mysql> CALL mysql.rds_stop_replication_for_channel('チャンネル名'); +--------------------------------------------------------+ | Message | +--------------------------------------------------------+ | Replication for channel 'チャンネル名' is down or disabled. | +--------------------------------------------------------+
レプリケーションの削除(リセット)
mysql> CALL mysql.rds_reset_external_source_for_channel ("チャンネル名"); +---------------------------------------------------------+ | message | +---------------------------------------------------------+ | Replication has been reset for channel 'チャンネル名' | +---------------------------------------------------------+